#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#include "scanner.h"
#include "tools.h"

static void run(const char *source)
{
    initScanner(source);
    int line = -1;
    for(;;)
    {
        Token token = scanToken();
        if(token.line != line)
        {
            printf("%4d ", token.line);
            line = token.line;
        }
        else{
            printf("    | ");
        }
        char *str = convert_to_str(token); // 将token转换为字符串
        printf("%s '%.*s'\n", str, token.length, token.start);

        if(token.type == TOKEN_EOF){
            break;
        }
    }
}

static void repl()
{
    char line[1024];    // 待分析的源代码字符串
    for(;;)
    {
        printf("> ");
        if(fgets(line, sizeof(line), stdin) == NULL)
        {
            printf("\n");
            break;
        }
        run(line);  // 调用run函数进行词法分析
    }
}

static char *readFile(const char *path)
{
    FILE *file = fopen(path, "rb");
    if(file == NULL)
    {
        fprintf(stderr, "无法打开文件！ \"%s\".\n", path);
        exit(EXIT_FAILURE); 
    }
    
    fseek(file, 0L, SEEK_END);  // 移动文件指针到末尾
    size_t fileSize = ftell(file); // ftell计算文件大小
    rewind(file);

    char *buffer = (char*)malloc(fileSize+1);
    if(buffer == NULL)
    {
        fprintf(stderr, "无法分配内存！ \"%s\".\n", path);
        exit(EXIT_FAILURE);
    }

    size_t byteRead = fread(buffer, sizeof(char), fileSize, file);
    if(byteRead < fileSize)
    {
        fprintf(stderr, "读取文件失败!  \"%s\".\n", path);
        exit(EXIT_FAILURE);
    }

    buffer[fileSize] = '\0';
    fclose(file);
    return buffer;  // 返回包含文件全部信息的字符串
}

static void runFile(const char *path)
{
    char *source = readFile(path);

    run(source);
// 释放动态分配的内存资源
    free(source);
}

// mian函数支持传递命令行参数
int main(int argc, const char *argv[])
{
    if(argc == 1)
    {
        // 交互式的输入源代码字符串，进行词法分析
        repl();
    }
    else if(argc == 2)
    {
        runFile(argv[1]);
    }
    else{
        fprintf(stderr, "Usage: scanner [path]\n");
        exit(EXIT_FAILURE);
    }
    return 0;
}
